home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / linux-bo / etherboo.000 / etherboo / etherboot-2.0 / netboot-freebsd / ni52.c < prev    next >
C/C++ Source or Header  |  1996-01-12  |  16KB  |  485 lines

  1. /* 
  2.  * Netboot driver for ni5210. Ken Yap <ken@syd.dit.csiro.au>
  3.  * 
  4.  * This driver is mostly adapted from Donald Becker's 3c507 driver for
  5.  * Linux since it was the clearest explanation of the 82586 chip I could
  6.  * find. It in turn was partly derived from the Crywnr packet driver.
  7.  * Parts of this driver were taken from Michael Hipp's ni5210 driver for
  8.  * Linux and the NCSA Telnet source provided more clues.
  9.  * 
  10.  * The 82586 is a strange beast. It's best to think of it as a
  11.  * coprocessor. The ni5210 shares memory between the PC and the 82586.
  12.  * Commands are sent to the 82586 by depositing it in memory and then
  13.  * hitting the 82568 with an attention signal on an ioport. The fun comes
  14.  * from the interesting mapping of memory. In the ni5210 the window appears
  15.  * to be aligned with the bottom of 82586 memory with aliasing throughout
  16.  * the address space so that 1FFF or 3FFF (depending on 8k or 16k memory
  17.  * installed) is also FFFFFF in the 82586 address space for the purpose
  18.  * of bootup. Unfortunately there is no way to tell whether we have
  19.  * 8k or 16k of memory installed without actually doing an init since
  20.  * this jumper info is not readily available to the software. */
  21.  
  22. #include "netboot.h"
  23.  
  24. #ifdef    NETBOOT32
  25. #define    fpeekw(w)    (*((short *)(w)))
  26. #endif
  27.  
  28. /* NI5210 IO addresses */
  29. #define NI52_RESET     0    /* writing to this address, resets the *
  30.                  * i82586 */
  31. #define NI52_ATTENTION 1    /* channel attention, kick the 586 */
  32. #define NI52_TDIS      2    /* Xmit disable */
  33. #define NI52_TENA      3    /* Xmit enable */
  34. #define NI52_INTENA    5    /* Interrupt enable */
  35. #define NI52_INTDIS    4    /* Interrupt disable */
  36. #define NI52_MAGIC1    6    /* dunno exact function */
  37. #define NI52_MAGIC2    7    /* dunno exact function */
  38.  
  39. #define NI52_MAGICVAL1 0x00    /* magic-values for ni5210 card */
  40. #define NI52_MAGICVAL2 0x55
  41.  
  42. #define NI52_ADDR0    0x02    /* ni5210 Ethernet addresses are 020701xxxxxx */
  43. #define NI52_ADDR1    0x07
  44. #define NI52_ADDR2    0x01
  45.  
  46. #define ni_reset586()    outb(eth_nic_base+NI52_RESET,0)
  47. #define    ni_intdis()    outb(eth_nic_base+NI52_INTDIS,0)
  48. #define    ni_tdis()    outb(eth_nic_base+NI52_TDIS,0)
  49. #define    ni_tena()    outb(eth_nic_base+NI52_TENA,0)
  50. #define ni_attn586()    outb(eth_nic_base+NI52_ATTENTION,0)
  51.  
  52. struct eth_header
  53. {
  54.     unsigned char    dst[ETHER_ADDR_SIZE];
  55.     unsigned char    src[ETHER_ADDR_SIZE];
  56.     unsigned short    type;
  57. };
  58.  
  59. unsigned short  eth_nic_base;
  60. unsigned short  eth_tx_link;
  61. unsigned short  eth_memsize;
  62. Address         eth_bmem;
  63. Address         eth_rmem;
  64. unsigned char  *eth_node_addr;
  65. short        aui;
  66.  
  67. /**************************************************************************
  68. The following two variables are used externally
  69. **************************************************************************/
  70. char            eth_driver[] = "ed0";
  71. char            packet[ETH_MAX_PACKET];
  72. int             packetlen;
  73.  
  74. /* The following came from 3c507.c, with some formatting cleanup. */
  75. /* 
  76.  * Details of the i82586.
  77.  * 
  78.  * You'll really need the databook to understand the details of this part,
  79.  * but the outline is that the i82586 has two separate processing units.
  80.  * Both are started from a list of three configuration tables, of which
  81.  * only the last, the System Control Block (SCB), is used after reset-time. 
  82.  * The SCB has the following fields: Status word Command word Tx/Command
  83.  * block addr. Rx block addr. The command word accepts the following
  84.  * controls for the Tx and Rx units: */
  85.  
  86. #define    CUC_START    0x0100
  87. #define    CUC_RESUME    0x0200
  88. #define    CUC_SUSPEND    0x0300
  89. #define    RX_START    0x0010
  90. #define    RX_RESUME    0x0020
  91. #define    RX_SUSPEND    0x0030
  92.  
  93. /* The Rx unit uses a list of frame descriptors and a list of data buffer
  94.  * descriptors.  We use full-sized (1518 byte) data buffers, so there is 
  95.  * a  one-to-one pairing of frame descriptors to buffer descriptors. 
  96.  * The Tx ("command") unit executes a list of commands that look like: 
  97.  * Status word    Written by the 82586 when the command is done.
  98.  * Command word    Command in lower 3 bits, post-command action in upper 3
  99.  * Link word    The address of the next command.
  100.  * Parameters    (as needed).
  101.  * Some definitions related to the Command Word are: */
  102.  
  103. #define CMD_EOL        0x8000    /* The last command of the list, stop. */
  104. #define CMD_SUSP    0x4000    /* Suspend after doing cmd. */
  105. #define CMD_INTR    0x2000    /* Interrupt after doing cmd. */
  106.  
  107. enum commands
  108. {
  109.     CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
  110.     CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
  111. };
  112.  
  113. /* Offsets to registers in the mailbox (SCB). */
  114. #define iSCB_STATUS    0x8
  115. #define iSCB_CMD    0xA
  116. #define iSCB_CBL    0xC    /* Command BLock offset. */
  117. #define iSCB_RFA    0xE    /* Rx Frame Area offset. */
  118.  
  119. /* 
  120.  * What follows in 'init_words[]' is the "program" that is downloaded to
  121.  * the 82586 memory.  It's mostly tables and command blocks, and starts 
  122.  * at the reset address 0xfffff6.  This is designed to be similar to the
  123.  * EtherExpress, thus the unusual location of the SCB at 0x0008.
  124.  * 
  125.  * Even with the additional "don't care" values, doing it this way takes
  126.  * less program space than initializing the individual tables, and I feel
  127.  * it's much cleaner.
  128.  * 
  129.  * The databook is particularly useless for the first two structures, I
  130.  * had to use the Crynwr driver as an example.
  131.  * 
  132.  * The memory setup is as follows: */
  133.  
  134. #define CONFIG_CMD    0x18
  135. #define SET_SA_CMD    0x24
  136. #define SA_OFFSET    0x2A
  137. #define IDLELOOP    0x30
  138. #define TDR_CMD        0x38
  139. #define TDR_TIME    0x3C
  140. #define DUMP_CMD    0x40
  141. #define DIAG_CMD    0x48
  142. #define SET_MC_CMD    0x4E
  143. #define DUMP_DATA    0x56    /* A 170 byte buffer for dump and Set-MC
  144.                 into. */
  145.  
  146. #define TX_BUF_START    0x0100
  147. #define TX_BUF_SIZE     (1518+14+20+16)    /* packet+header+TBD */
  148.  
  149. #define RX_BUF_START    0x0800
  150. #define RX_BUF_SIZE     (1518+14+18)    /* packet+header+RBD */
  151.  
  152. /* 
  153.  * That's it: only 86 bytes to set up the beast, including every extra
  154.  * command available.  The 170 byte buffer at DUMP_DATA is shared between
  155.  * the Dump command (called only by the diagnostic program) and the
  156.  * SetMulticastList command. 
  157.  * 
  158.  * To complete the memory setup you only have to write the station address 
  159.  * at SA_OFFSET and create the Tx & Rx buffer lists.
  160.  * 
  161.  * The Tx command chain and buffer list is setup as follows: A Tx command
  162.  * table, with the data buffer pointing to... A Tx data buffer descriptor. 
  163.  * The packet is in a single buffer, rather than chaining together several 
  164.  * smaller buffers. A NoOp command, which initially points to itself, And
  165.  * the packet data.
  166.  * 
  167.  * A transmit is done by filling in the Tx command table and data buffer,
  168.  * re-writing the NoOp command, and finally changing the offset of the
  169.  * last command to point to the current Tx command.  When the Tx command
  170.  * is finished, it jumps to the NoOp, when it loops until the next Tx
  171.  * command changes the "link offset" in the NoOp.  This way the 82586
  172.  * never has to go through the slow restart sequence. */
  173.  
  174. unsigned short  init_words[] =
  175. {
  176.     /* System Configuration Pointer (SCP). */
  177.     0x0001,            /* Set bus size to 8 bits. */
  178.     0, 0,            /* pad words. */
  179.     0x0000, 0x0000,        /* ISCP phys addr, set in
  180.                  * init_82586_mem(). */
  181.  
  182.     /* Intermediate System Configuration Pointer (ISCP). */
  183.     0x0001,            /* Status word that's cleared when init is 
  184.                  * done. */
  185.     0x0008, 0, 0,        /* SCB offset, (skip, skip) */
  186.  
  187.     /* System Control Block (SCB). */
  188.     0, 0xF000 | CUC_START,/* SCB status and cmd. */
  189.     CONFIG_CMD,        /* Command list pointer, points to
  190.                  * Configure. */
  191.     RX_BUF_START,        /* Rx block list. */
  192.     0, 0, 0, 0,        /* Error count: CRC, align, buffer,
  193.                  * overrun. */
  194.  
  195.     /* 0x0018: Configure command.  Change to put MAC data with packet. 
  196.      * 
  197.      */
  198.     0, CmdConfigure,    /* Status, command. */
  199.     SET_SA_CMD,        /* Next command is Set Station Addr. */
  200.     0x0804,            /* "4" bytes of config data, 8 byte FIFO. */
  201.     0x2e40,            /* Magic values, including MAC data
  202.                  * location. */
  203.     0,            /* Unused pad word. */
  204.  
  205.     /* 0x0024: Setup station address command. */
  206.     0, CmdSASetup,
  207.     SET_MC_CMD,        /* Next command. */
  208.     0xaa00, 0xb000, 0x0bad,    /* Station address (to be filled in) */
  209.  
  210.     /* 0x0030: NOP, looping back to itself.  Point to first Tx buffer
  211.      * to Tx. */
  212.     0, CmdNOp, IDLELOOP, 0 /* pad */ ,
  213.  
  214.     /* 0x0038: A unused Time-Domain Reflectometer command. */
  215.     0, CmdTDR, IDLELOOP, 0,
  216.  
  217.     /* 0x0040: An unused Dump State command. */
  218.     0, CmdDump, IDLELOOP, DUMP_DATA,
  219.  
  220.     /* 0x0048: An unused Diagnose command. */
  221.     0, CmdDiagnose, IDLELOOP,
  222.  
  223.     /* 0x004E: An empty set-multicast-list command. */
  224.     0, CmdMulticastList, IDLELOOP, 0,
  225. };
  226.  
  227. /* End of stuff from 3c507.c */
  228.  
  229. int mem_probe P((void));
  230. int i82586_probe P((void));
  231.  
  232. /**************************************************************************
  233. ETH_PROBE - Look for an adapter
  234. **************************************************************************/
  235. int eth_probe()
  236. {
  237.     int             i;
  238.     char           *name;
  239.     unsigned short  chksum;
  240.     unsigned char   c;
  241.  
  242.     unsigned short *port;
  243.     static unsigned short ports[] =
  244.     {0x300, 0x280, 0x360, 0x320, 0x340, 0};
  245.  
  246.     for (port = ports; *port != 0; port++)
  247.     {
  248.         unsigned short  ioaddr = *port;
  249.         if (!(inb(ioaddr + NI52_MAGIC1) == NI52_MAGICVAL1) ||
  250.             !(inb(ioaddr + NI52_MAGIC2) == NI52_MAGICVAL2))
  251.             continue;
  252.         eth_nic_base = ioaddr;
  253.         eth_node_addr = arptable[ARP_CLIENT].node;
  254.         for (i = 0; i < 6; i++)
  255.             eth_node_addr[i] = inb(eth_nic_base + i);
  256.         if (eth_node_addr[0] != NI52_ADDR0
  257.             || eth_node_addr[1] != NI52_ADDR1
  258.             || eth_node_addr[2] != NI52_ADDR2)
  259.             continue;
  260.         printf("\r\nNI5210 base 0x%x, ", eth_nic_base);
  261.         /* we found the IObase, now try to find membase */
  262.         if (mem_probe())
  263.             break;
  264.     }
  265.     printf("memory 0x%X size 0x%x addr ", eth_bmem, eth_memsize);
  266.     for (i = 0; i < 6; i++)
  267.     {
  268.         printf("%b", (int)eth_node_addr[i]);
  269.         if (i < 5)
  270.             printf(":");
  271.     }
  272.     printf("\r\n");
  273.     eth_reset();
  274.     return (eth_nic_base != 0 && eth_bmem != 0);
  275. }
  276.  
  277. int mem_probe()
  278. {
  279.     static Address  memaddrs[] =
  280.     {0xdc000, 0xc0000, 0xc4000, 0xc8000, 0xcc000, 0xd0000, 0xd4000,
  281.     0xd8000, 0xdc000, 0};
  282.     int             i;
  283.  
  284.     for (i = 0; (eth_bmem = memaddrs[i]) != 0; i++)
  285.     {
  286.         /* 8K-check */
  287.         bzero(eth_bmem, eth_memsize = 0x2000);
  288.         if (fbsame(eth_bmem, 0, eth_memsize) && i82586_probe())
  289.             break;
  290.         /* 16K-check */
  291.         bzero(eth_bmem, eth_memsize = 0x4000);
  292.         if (fbsame(eth_bmem, 0, eth_memsize) && i82586_probe())
  293.             break;
  294.     }
  295.     return (eth_bmem != 0, 1);
  296. }
  297.  
  298. int i82586_probe()
  299. {
  300.     static ushort probe_words[] =
  301.     { 1, 8, 0, 0,            /* ISCP */
  302.       0, 0, 0, 0, 0, 0, 0, 0 };    /* SCB */
  303.  
  304.     ni_intdis();
  305.     ni_tdis();
  306.     ni_reset586();
  307.     DELAY(2000);
  308. #ifdef    NETBOOT32
  309.     /* Write the SCP words at 0xfff6 (address-aliased to 0xfffff6). */
  310.     bcopy(init_words, (char *)(eth_bmem + eth_memsize - 10), 10);
  311.     /* Write the ISCP, SCB and configure command words at 0x0000. */
  312.     bcopy(probe_words, (char *)eth_bmem, sizeof(probe_words));
  313. #endif
  314. #ifdef    NETBOOT16
  315.     /* Write the SCP words at 0xfff6 (address-aliased to 0xfffff6). */
  316.     bcopyf(init_words, eth_bmem + eth_memsize - 10, 10);
  317.     /* Write the ISCP, SCB and configure command words at 0x0000. */
  318.     bcopyf(probe_words, eth_bmem, sizeof(probe_words));
  319. #endif
  320.     ni_reset586();
  321.     ni_attn586();
  322.     DELAY(2000);
  323.     return (fpeekw(eth_bmem) == 0);
  324. }
  325.  
  326. /**************************************************************************
  327. ETH_RESET - Reset adapter
  328. **************************************************************************/
  329. int eth_reset()
  330. {
  331.     ni_tdis();
  332.     ni_reset586();
  333.     DELAY(2000);
  334. #ifdef    NETBOOT32
  335.     /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
  336.     bcopy(init_words, (char *)(eth_bmem + eth_memsize - 10), 10);
  337.     /* Write the words at 0x0000. */
  338.     bcopy(init_words + 5, (char *)eth_bmem, sizeof(init_words) - 10);
  339.     /* Fill in the station address. */
  340.     bcopy(eth_node_addr, (char *)(eth_bmem + SA_OFFSET), ETHER_ADDR_SIZE);
  341. #endif
  342. #ifdef    NETBOOT16
  343.     /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
  344.     bcopyf(init_words, eth_bmem + eth_memsize - 10, 10);
  345.     /* Write the words at 0x0000. */
  346.     bcopyf(init_words + 5, eth_bmem, sizeof(init_words) - 10);
  347.     /* Fill in the station address. */
  348.     bcopyf(eth_node_addr, eth_bmem + SA_OFFSET, ETHER_ADDR_SIZE);
  349. #endif
  350.     eth_tx_link = IDLELOOP + 4;    /* location of NOP block tx address */
  351.     ni_reset586();
  352.     ni_attn586();
  353.     DELAY(2000);
  354.     /* This was time consuming to track down: you need to give two
  355.      * channel attention signals to reliably start up the i82586. */
  356.     if (fpeekw(eth_bmem + iSCB_STATUS) == 0)
  357.     {
  358.         printf("i82586 initialization timed out with status %x, cmd %x\r\n",
  359.                fpeekw(eth_bmem + iSCB_STATUS),
  360.                fpeekw(eth_bmem + iSCB_CMD));
  361.         /* Issue channel-attn again */
  362.         ni_attn586();
  363.         DELAY(2000);
  364.     }
  365.     ni_tena();
  366. printf("iSCB_STATUS = %x\r\n", fpeekw(eth_bmem + iSCB_STATUS));
  367.     return (fpeekw(eth_bmem + iSCB_STATUS) != 0);
  368. }
  369.  
  370. /**************************************************************************
  371. ETH_TRANSMIT - Transmit a frame
  372. **************************************************************************/
  373. #ifdef    __STDC__
  374. eth_transmit(char *d, unsigned short t, unsigned short s, char *p)
  375. #else
  376. eth_transmit(d, t, s, p)
  377.     char           *d;        /* Destination */
  378.     unsigned short  t;        /* Type */
  379.     unsigned short  s;        /* size */
  380.     char           *p;        /* Packet */
  381. #endif
  382. {
  383.     ushort        a;
  384.     struct eth_header    e;
  385.     static ushort    buffer[11] = {
  386.         0x0000,            /* Tx status */
  387.         CmdTx,            /* Tx command */
  388.         TX_BUF_START + 16,    /* Next command is a NoOp. */
  389.         TX_BUF_START + 8,    /* Data Buffer offset. */
  390.         /* Data buffer descriptor. */
  391.         0x8000,            /* Byte count parameter. */
  392.         -1,            /* No next data buffer. */
  393.         TX_BUF_START + 22 + 0,    /* Buffer follows
  394.                      * the NoOp  *
  395.                      * command. */
  396.         0x0000,        /* Buffer address high bits (always zero). 
  397.                  * 
  398.                  */
  399.         /* Loop-back NoOp command. */
  400.         0x0000,            /* Tx status */
  401.         CmdNOp,            /* Tx command */
  402.         TX_BUF_START + 16    /* Next is myself. */
  403.     };
  404.  
  405. printf("Send %x bytes type %x from %X\r\n", s, t, p);
  406.     /* assemble header first */
  407.     bcopy(d, e.dst, ETHER_ADDR_SIZE);
  408.     bcopy(eth_node_addr, e.src, ETHER_ADDR_SIZE);
  409.     e.type = htons(t);
  410.     /* copy header then data into shared memory */
  411. #ifdef    NETBOOT32
  412.     bcopy(&e, (char *)(eth_bmem + TX_BUF_START + 22), sizeof(e));
  413.     bcopy(p, (char *)(eth_bmem + TX_BUF_START + 22 + sizeof(e)), s);
  414. #endif
  415. #ifdef    NETBOOT16
  416.     bcopyf(&e, eth_bmem + TX_BUF_START + 22, sizeof(e));
  417.     bcopyf(p, eth_bmem + TX_BUF_START + 22 + sizeof(e), s);    /* data */
  418. #endif
  419. #ifdef    NETBOOT32
  420. {
  421. char    b[100], *bp;
  422. int    i;
  423. bp = b;
  424. bcopy(eth_bmem + TX_BUF_START + 22, b, sizeof(b));
  425. for (i = 0; i < sizeof(b); ++i)
  426. {
  427.     printf(i % 20 ? " " : "\r\n");
  428.     printf("%b", *bp++);
  429. }
  430. printf("\r\n");
  431. }
  432. #endif
  433.     s += sizeof(e);                /* for ether header */
  434.     if (s < ETH_MIN_PACKET)
  435.                 s = ETH_MIN_PACKET;
  436.     buffer[4] = s | 0x8000;
  437.     a = TX_BUF_START;
  438. printf("Modifying word at offset %d\r\n", eth_tx_link);
  439. #ifdef    NETBOOT32
  440.     bcopy(buffer, (char *)(eth_bmem + TX_BUF_START), sizeof(buffer));
  441.     /*bcopy(&a, (char *)(eth_bmem + eth_tx_link), sizeof(a));*/
  442. #endif
  443. #ifdef    NETBOOT16
  444.     bcopyf(buffer, eth_bmem + TX_BUF_START, sizeof(buffer));
  445.     bcopyf(&a, eth_bmem + eth_tx_link, sizeof(a));
  446. #endif
  447.     eth_tx_link = TX_BUF_START + 20;    /* NOP block address */
  448. printf("SCB status = %x\r\n", fpeekw(eth_bmem + iSCB_STATUS));
  449. DELAY(2000);
  450. printf("Transmit status = %x\r\n", fpeekw(eth_bmem + TX_BUF_START));
  451.     return (0);
  452. }
  453.  
  454. /**************************************************************************
  455. ETH_POLL - Wait for a frame
  456. **************************************************************************/
  457. eth_poll()
  458. {
  459. }
  460.  
  461. /* a surrogate */
  462.  
  463. #ifdef    __STDC__
  464. DELAY(int val)
  465. #else
  466. DELAY(val)
  467.     int    val;
  468. #endif
  469. {
  470.     int    c;
  471.  
  472.     for (c = val; c > 0; --c)
  473.         twiddle();
  474. }
  475.  
  476. #ifdef    NETBOOT32
  477. int fbsame(char *p, int c, int n)
  478. {
  479.     while (n-- > 0)
  480.         if (*p++ != c)
  481.             return (0);
  482.     return (1);
  483. }
  484. #endif
  485.